package cn.hfjava.kz.controller;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hfjava.kz.common.UpdateGroup;
import cn.hfjava.kz.common.VerCodeGenerateUtil;
import cn.hfjava.kz.entity.dto.LoginUserDTO;
import cn.hfjava.kz.entity.dto.UserFormDTO;
import cn.hfjava.kz.entity.dto.UserQueryDTO;
import cn.hfjava.kz.entity.po.Permission;
import cn.hfjava.kz.entity.po.Role;
import cn.hfjava.kz.entity.po.User;
import cn.hfjava.kz.entity.vo.PageVO;
import cn.hfjava.kz.entity.vo.UserVO;
import cn.hfjava.kz.service.PermissionService;
import cn.hfjava.kz.service.RoleService;
import cn.hfjava.kz.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.groups.Default;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author 29264
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth")
@Tag(name = "用户管理模块", description = "用户管理模块接口")
public class UserController {
    @Resource
    JavaMailSenderImpl mailSender;
    private final UserService userService;
    private final RoleService roleService;
    private final PermissionService permissionService;
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);

    @Resource
    private BCryptPasswordEncoder passwordEncoder;


    @PostMapping("/login")
    @Operation(summary = "用户登录", description = "用户登录接口")
    public SaResult login(@RequestBody @Validated LoginUserDTO loginUserDto,
                          HttpServletRequest request) {
        //HttpSession session = request.getSession();
//        Map<String, String> codeMap = (Map<String, String>) session.getAttribute("verCode");  // 获取验证码
//        System.out.println("验证码：" + codeMap.get("code"));
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUsername, loginUserDto.getUsername());
        User user = userService.getOne(lqw);
//        if (codeMap.get("code") == null) {
//            return SaResult.error("验证码已过期，请重新获取");
//        } else if (!codeMap.get("code").equals(loginUserDto.getCode())) {
//            return SaResult.error("验证码错误，请重新输入");
//        }

        if (Objects.isNull(user)) {
            return SaResult.error("用户不存在，请重新输入");
        } else {
            if (!passwordEncoder.matches(loginUserDto.getPassword(), user.getPassword())) {
                return SaResult.error("密码错误,请重新输入");
            } else if (user.getStatus() == 1) {
                return SaResult.error("账号已被锁定,请联系管理员");
            } else {
                StpUtil.login(user.getId(), SaLoginConfig
                        .setExtra("username", user.getUsername()));
                System.out.println("Logged in user ID: " + user.getId() + ", Username: " + user.getUsername());
                String tokenName = StpUtil.getTokenName();
                String tokenValue = StpUtil.getTokenValue();
                user.setTokenName(tokenName);
                user.setTokenValue(tokenValue);
                user.setPassword("");
                // 第3步，返回给前端
                return SaResult.data(user);
            }
        }
    }


    @Operation(summary = "获取当前登录的用户信息")
    @PostMapping("/info")
    public SaResult info() {
        Integer userId = Integer.valueOf(StpUtil.getLoginId().toString());   // 获取当前会话账号id, 如果未登录，则抛出异常
        User user = userService.getById(userId);
        user.setPassword("");
        return SaResult.ok().setData(user);
    }


    @Operation(summary = "退出登录")
    @GetMapping("/logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }


    @Operation(summary = "重置密码")
    @PostMapping("/resetPassword")
    public SaResult resetPassword() {
        Integer userId = Integer.valueOf(StpUtil.getLoginId().toString());
        User user = userService.getById(userId);
        String phone = user.getPhone();
        String password = phone.substring(phone.length() - 6);
        String ciphertext = passwordEncoder.encode(password);
        user.setPassword(ciphertext);
        LambdaUpdateWrapper<User> uw = new LambdaUpdateWrapper<>();
        uw.set(User::getPassword, ciphertext);
        uw.eq(User::getId, userId);
        userService.update(null, uw);
        return SaResult.ok("重置密码成功");
    }

    @Operation(summary = "新增用户")
    @PostMapping("/add")
    public SaResult addUser(@Validated(Default.class) @RequestBody UserFormDTO userDto) {
        //该用户名已存在，或被其他用户占用
        User userEntity = new User();
        //将前端传入的UserDTO对象中的数据拷贝到User持久对象
        BeanUtils.copyProperties(userDto, userEntity);
        userEntity.setPassword(passwordEncoder.encode(userDto.getPassword()));
        userService.save(userEntity);
        return SaResult.ok("保存用户信息成功");
    }


    @Operation(summary = "修改用户")
    @PutMapping("/update")
    public SaResult updateUser(@Validated(UpdateGroup.class) @RequestBody UserFormDTO userDto) {
        //该用户名不存在，修改失败
        User userEntity = new User();
        //将前端传入的UserDTO对象中的数据拷贝到User持久对象
        BeanUtils.copyProperties(userDto, userEntity);
        userEntity.setPassword(passwordEncoder.encode(userDto.getPassword()));
        userService.updateById(userEntity);
        return SaResult.ok("修改用户信息成功");
    }

    //根据（name、userName、roleId、status）组合条件分页查询用户信息(隐藏内置超级管理员)
    @Operation(summary = "分页查询用户")
    @PostMapping("/listPage")
    public SaResult listPage(@RequestBody UserQueryDTO userQueryDto) {
        PageVO<UserVO> pageVO = userService.findByPage(userQueryDto);
        return SaResult.ok("查询成功").setData(pageVO);
    }


    @DeleteMapping("/delete/{id}")
    @Operation(summary = "逻辑删除用户")
    public SaResult deleteUser(@PathVariable Integer id) {
        Integer currentUserId = Integer.valueOf(StpUtil.getLoginId().toString());
        if (currentUserId.equals(id)) {
            return SaResult.error("当前登录的用户不能删除");
        }
        User user = userService.getById(id);
        if (user == null || user.getDeleted() == 1) {
            return SaResult.error("此用户不存在");
        }
        int count = user.getRoleId();
        if (count == 1) {
            return SaResult.error("系统管理员不能删除");
        }
        boolean hasAssignedRoles;
        if (count >= 1 && count <= 4) {
            hasAssignedRoles = true;
        } else {
            hasAssignedRoles = false;
        }
        if (hasAssignedRoles) {
            return SaResult.error("此用户已授予角色权限不能删除");
        }
        userService.removeById(id);
        return SaResult.ok("删除用户成功");
    }

    @DeleteMapping("stDelete")
    @Operation(summary = "批量删除用户信息", description = "批量删除用户信息接口")
    public SaResult deleteByList(@RequestBody List<Integer> idList) {
        userService.removeByIds(idList);
        System.out.println(SaResult.ok("删除成功"));
        return SaResult.ok("删除成功");
    }


    //绑定角色 (某个用户绑定某一个角色)
    @PostMapping("/bindRole")
    @Operation(summary = "绑定角色到用户", description = "根据用户ID和角色ID绑定角色到用户")
    public SaResult bindRole(@RequestParam Integer userId, @RequestParam Integer roleId) {
        // 验证用户和角色是否存在
        User user = userService.getById(userId);
        if (user == null) {
            return SaResult.error("用户不存在");
        }

        Role role = roleService.getById(roleId);
        if (role == null) {
            return SaResult.error("角色不存在");
        }

        // 更新用户的roleId
        user.setRoleId(roleId);
        userService.updateById(user);

        // 可以在这里添加额外的逻辑，例如更新权限缓存等

        return SaResult.ok("角色绑定成功");
    }


    // 1、用户登录（管理员、考生） 不同的用户登录系统拥有不同的菜单权限、数据隔离、按钮权限
    // 2、用户安全退出
    // 3、获取当前登录用户信息
    // 4、重置密码(用户手机号后六位作为密码，加密后存储到数据库)
    // 5、上传头像
    // 6、新增管理员用户   （不能使用实体类User，针对前端封装独立XxxDTO接收前端表单数据）
    // 7、根据（name、userName、roleId、status）组合条件分页查询用户信息(隐藏内置超级管理员)
    // 8、根据userId修改用户信息
    // 9、绑定角色 (某个用户绑定某一个角色)  角色：一系列权限的集合(如：系统管理员、普通用户、 考生、教师等)、权限：菜单权限、按钮权限、数据增、删、改、查、导入、导出、重置密码、批量操作等权限、数据权限
    // 10、根据userId删除指定的用户(不能删除当前登录用户)、此用户如果有相关联的数据，无法删除

    //发送验证码
    @Operation(summary = "发送验证码")
    @PostMapping("/sendCode")
    public SaResult sendCode(@RequestParam("email") @Validated String email,
                             HttpServletRequest request) {
        HttpSession session = request.getSession();

        String code = VerCodeGenerateUtil.getCode();
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//         session.setAttribute("code",code);
        LocalDateTime now = LocalDateTime.now();
        String time = now.format(fmt);
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        map.put("email", email);

        //验证码和邮箱，一起放入session中
        session.setAttribute("verCode", map);
//        System.out.println(session.getAttribute("verCode"));
        Map<String, String> codeMap = (Map<String, String>) session.getAttribute("verCode");
//        System.out.println(codeMap);
        //创建计时线程池，到时间自动移除验证码
        try {
            scheduledExecutorService.schedule(new Thread(() -> {
                if (email.equals(codeMap.get("email"))) {
                    session.removeAttribute("verCode");
                }
            }), 5 * 60, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("2857516584@qq.com");
        message.setTo(email);
        message.setSubject("发送邮件");
        message.setText("邮件内容" + code);
//         System.out.println(time);;
        try {
            //发送邮件
            mailSender.send(message);
        } catch (MailException e) {
            //邮箱是无效的，或者发送失败
            return SaResult.error("发送失败");
        }

        return SaResult.ok();
    }

    @Operation(summary = "验证验证码")
    @PostMapping("/checkCode")
    public SaResult checkCode(@RequestParam("code") @Validated String code, HttpServletRequest request) {
        HttpSession session = request.getSession();
        Map<String, String> codeMap = (Map<String, String>) session.getAttribute("verCode");

        if (codeMap.get("code") == null) {
            return SaResult.error("验证码为空或者已过期");
        }
        if (codeMap.get("code").equals(code)) {
            return SaResult.ok();
        } else {
            return SaResult.error("验证码错误");
        }
    }

    @Operation(summary = "修改密码")
    @PostMapping("/updatePassword")
    public SaResult updatePassword(@RequestParam("password") String password, @RequestParam("checkPassword") String checkPassword) {

        if (password.equals(checkPassword)) {
            Integer userId = StpUtil.getLoginIdAsInt();
            User user = userService.getById(userId);
            String ciphertext = passwordEncoder.encode(password);
            user.setPassword(ciphertext);
            LambdaUpdateWrapper<User> uw = new LambdaUpdateWrapper<>();
            uw.eq(User::getId, userId);
            uw.set(User::getPassword, ciphertext);
            userService.update(null, uw);
            return SaResult.ok("密码修改成功");
        } else {
            return SaResult.error("两次密码不一致");
        }

    }




    @Operation(summary = "获取菜单权限",description = "根据用户ID获取菜单权限列表")
    @GetMapping("/menuPerms")
    public SaResult getMenuPerms(@RequestParam("userId") Integer userId) {
        List<Permission> menuTree =
                permissionService.getMenuTree(userId);
        return SaResult.data(menuTree);
    }
}
